<div class="standardContainer">
    <div class="ui basic segment">
        <h2>Uptime Monitor</h2>
        <p>Check the online state of proxied targets</p>
    </div>
    <div class="ui divider"></div>
    <div id="utmrender" class="ui basic segment">
        <div class="ui basic segment">
            <h4 class="ui header">
                <i class="red remove icon"></i>
                <div class="content">
                    Uptime Monitoring service is currently unavailable
                    <div class="sub header">This might be caused by an error in cluster communication within the host servers. Please wait for administrator to resolve the issue.</div>
                </div>
            </h4> 
        </div>
    </div>
    <div align="center">
        <button class="ui basic circular green icon button" onclick="reloadUptimeList();"><i class="refresh icon"></i></button>   
    </div>
</div>


<script>
    var uptime5xxErrorMessage = {
        "500": "Internal Server Error",
        "501": "Not Implemented",
        "502": "Bad Gateway",
        "503": "Service Unavailable",
        "504": "Gateway Timeout",
        "505": "HTTP Version Not Supported",
        "506": "Variant Also Negotiates",
        "507": "Insufficient Storage",
        "508": "Loop Detected",
        "510": "Not Extended",
        "511": "Network Authentication Required",
        "520": "Web Server Returned an Unknown Error (Cloudflare)",
        "521": "Web Server is Down (Cloudflare)",
        "522": "Connection Timed Out (Cloudflare)",
        "523": "Origin is Unreachable (Cloudflare)",
        "524": "A Timeout Occurred (Cloudflare)",
        "525": "SSL Handshake Failed (Cloudflare)",
        "526": "Invalid SSL Certificate (Cloudflare)",
        "527": "Railgun Error (Cloudflare)",
        "530": "Site is Frozen (Pantheon)"
    }

        $('#utmEnable').checkbox({
          onChange: function() {
            var utmEnable = $('input[name="utmEnable"]').is(":checked");
            $.post({
              url: '/api/toggle-utm',
              data: {utmEnable: utmEnable},
              success: function(response) {
                console.log(response);
              },
              error: function(error) {
                console.log(error);
              }
            });
          }
        });

    function initUptimeTable(){
        $.get("/api/utm/list", function(data){
            let records = data;
            renderRecords(records);
        })
    }
    initUptimeTable();

    function reloadUptimeList(){
        $("#utmrender").html(`<div class="ui utmloading segment">
        <div class="ui active inverted dimmer" style="z-index: 2;">
            <div class="ui text loader">Loading</div>
        </div>
        <br><br><br><br>
        </div>`);
        setTimeout(initUptimeTable, 300);
    }

    //For every 5 minutes
    setInterval(function(){
        $.get("/api/utm/list", function(data){
            console.log("Status Updated");
            records = data;
            renderRecords(records);
        });
    }, (300 * 1000));
    
    function renderRecords(records){
        $("#utmrender").html("");
        for (let [key, value] of Object.entries(records)) {
            renderUptimeData(key, value);
        }
    }

    function format_time(s) {
        const date = new Date(s * 1e3);
        return(date.toLocaleString());
    }

    function resolveUptime5xxErrorMessage(errorCode){
        if (uptime5xxErrorMessage[errorCode] != undefined){
            return uptime5xxErrorMessage[errorCode]
        }else{
            return "Unknown Error";
        }
    }

    function showStatusDotInfo(targetDot){
        $(".statusbar .selectedDotInfo").hide();
        let payload = $(targetDot).attr("payload");
        let statusData = JSON.parse(decodeURIComponent(payload)); 
        let statusDotInfoEle = $(targetDot).parent().parent().find(".selectedDotInfo");
        let statusInfoEle = $(statusDotInfoEle).find(".status_dot_status_info");
        //Fill in the data to the info box
        $(statusDotInfoEle).find(".status_dot_timestamp").text(format_time(statusData.Timestamp));
        $(statusDotInfoEle).find(".status_dot_latency").text(statusData.Latency + "ms");
        $(statusDotInfoEle).find(".status_dot_status_code").text(statusData.StatusCode);
        

        //Set the class of the info box if status code is 5xx
        $(statusDotInfoEle).removeClass("yellow");
        $(statusDotInfoEle).removeClass("red");
        $(statusDotInfoEle).removeClass("green");
        if (statusData.StatusCode >= 500 && statusData.StatusCode < 600){
            $(statusDotInfoEle).addClass("yellow");
            $(statusInfoEle).text(httpErrorStatusCodeToText(statusData.StatusCode));
        }else if (statusData.StatusCode == 0 && !statusData.Online){
            $(statusDotInfoEle).addClass("red");
            $(statusInfoEle).text("Upstream is offline");
        }else{
            $(statusDotInfoEle).addClass("green");
            $(statusInfoEle).text("Upstream Online");
        }

        $(statusDotInfoEle).show();
    }


    function renderUptimeData(key, value){
        if (value.length == 0){
            return
        }

        let id = value[0].ID;
        let name = value[0].Name;
        let url = value[value.length - 1].URL;
        let protocol = value[0].Protocol;

        //Generate the status dot
        let statusDotList = ``;
        for(var i = 0; i < (288 - value.length); i++){
            //Padding
            statusDotList += `<div class="padding statusDot"></div>`
        }

        let ontimeRate = 0;
        for (var i = 0; i < value.length; i++){
            //Render status to html
            let thisStatus = value[i];
            let dotType = "";
            let statusCode = thisStatus.StatusCode;
            let statusDotPayload = encodeURIComponent(JSON.stringify(thisStatus));

            if (!thisStatus.Online && statusCode == 0){
                dotType = "offline";
            }else if (statusCode < 200){
                //1xx
                dotType = "error";
                ontimeRate++;
            }else if (statusCode < 300){
                //2xx
                dotType = "online";
                ontimeRate++;
            }else if (statusCode < 400){
                //3xx
                dotType = "online";
                ontimeRate++;
            }else if (statusCode < 500){
                //4xx
                dotType = "error";
                ontimeRate++;
            }else if (statusCode < 600){
                //5xx
                dotType = "error";
            }else {
                dotType = "offline";
            }
        
            let datetime = format_time(thisStatus.Timestamp);
            statusDotList += `<div title="${datetime}" class="${dotType} statusDot" payload="${statusDotPayload}" onclick="showStatusDotInfo(this);"></div>`
        }

        ontimeRate = ontimeRate / value.length * 100;
        let ontimeColor = "#df484a"
        if (ontimeRate > 0.8){
            ontimeColor = "#3bd671";
        }else if(ontimeRate > 0.5) {
            ontimeColor = "#f29030";
        }
        //Check of online status now
        let currentOnlineStatus = "Unknown";
        let onlineStatusCss = ``;
        let reminderEle = ``;
        if (value[value.length - 1].Online){
            currentOnlineStatus = `<i class="circle icon"></i> Online`;
            onlineStatusCss = `color: #3bd671;`;
        }else{
            if (value[value.length - 1].StatusCode >= 500 && value[value.length - 1].StatusCode < 600){
                var latestStatusCode = value[value.length - 1].StatusCode
                currentOnlineStatus = `<i class="exclamation circle icon"></i>${latestStatusCode} - ${resolveUptime5xxErrorMessage(latestStatusCode)}`;
                onlineStatusCss = `color: #f38020;`;
                reminderEle = `<small style="${onlineStatusCss}">Downstream proxy server is responsive but returning server error</small>`;
            }else if (value[value.length - 1].StatusCode >= 400 && value[value.length - 1].StatusCode <= 405){
                let latestStatusCode = value[value.length - 1].StatusCode;
                switch(latestStatusCode){
                    case 400:
                        currentOnlineStatus = `<i class="exclamation circle icon"></i> Bad Request`;
                        break;
                    case 401:
                        currentOnlineStatus = `<i class="exclamation circle icon"></i> Unauthorized`;
                        break;
                    case 403:
                        currentOnlineStatus = `<i class="exclamation circle icon"></i> Forbidden`;
                        break;
                    case 404: 
                        currentOnlineStatus = `<i class="exclamation circle icon"></i> Not Found`;
                        break; 
                    case 405: 
                        currentOnlineStatus = `<i class="exclamation circle icon"></i> Method Not Allowed`;
                        break;
                    default:
                        currentOnlineStatus = `<i class="exclamation circle icon"></i> Status Code: ${latestStatusCode}`;
                        break;
                }
                
                onlineStatusCss = `color: #f38020;`;
                reminderEle = `<small style="${onlineStatusCss}">Target online but not accessible</small>`;
                
            }else{
                currentOnlineStatus = `<i class="circle icon"></i> Offline`;
                onlineStatusCss = `color: #df484a;`;
            }
           
        }

        //Generate the html
        $("#utmrender").append(`<div class="ui basic segment statusbar">
            <div class="domain">
                <div style="position: absolute; top: 0; right: 0.4em;">
                    <p class="onlineStatus" style="display: inline-block; font-size: 1.2em; padding-right: 0.5em; padding-left: 0.3em; ${onlineStatusCss}">${currentOnlineStatus}</p>
                </div>
                <div>
                    <h3 class="ui header" style="margin-bottom: 0.2em;">${name}</h3>
                    <a href="${url}" target="_blank">${url}</a> | <span style="color: ${ontimeColor};">${(ontimeRate).toFixed(2)}%<span>
                </div>
                <div class="ui basic label protocol" style="position: absolute; bottom: 0; right: 0.2em; margin-bottom: -0.6em;">
                    proto: ${protocol}
                </div>
            </div>
            <div class="status" style="marign-top: 1em;">
                ${statusDotList}
            </div>
            ${reminderEle}
            <div class="ui basic segment selectedDotInfo" style="display:none; border: 0.4em;">
                <div class="ui list">
                    <div class="item"><b>Timestamp</b>: <span class="status_dot_timestamp"></span></div>
                    <div class="item"><b>Latency</b>: <span class="status_dot_latency"></span></div>
                    <div class="item"><b>Status Code</b>: <span class="status_dot_status_code"></span></div>
                    <div class="item"><b>Status Info</b>: <span class="status_dot_status_info"></span></div>
                </div>
                <button onclick="$(this).parent().hide();" style="position: absolute; right: 0.4em; top: 0.6em;" class="ui basic tiny circular icon button"><i class="ui times icon"></i></button>
            </div>
            <div class="ui divider"></div>
        </div>`);
    }
    
    function httpErrorStatusCodeToText(statusCode){
        switch(statusCode){
            case 400:
            return "Bad Request";
            case 401:
            return "Unauthorized";
            case 403:
            return "Forbidden";
            case 404:
            return "Not Found";
            case 405:
            return "Method Not Allowed";
            case 500:
            return "Internal Server Error";
            case 501:
            return "Not Implemented";
            case 502:
            return "Bad Gateway";
            case 503:
            return "Service Unavailable";
            case 504:
            return "Gateway Timeout";
            case 505:
            return "HTTP Version Not Supported";
            case 506:
            return "Variant Also Negotiates";
            case 507:
            return "Insufficient Storage";
            case 508:
            return "Loop Detected";
            case 510:
            return "Not Extended";
            case 511:
            return "Network Authentication Required";
            case 520:
            return "Web Server Returned an Unknown Error (Cloudflare)";
            case 521:
            return "Web Server is Down (Cloudflare)";
            case 522:
            return "Connection Timed Out (Cloudflare)";
            case 523:
            return "Origin is Unreachable (Cloudflare)";
            case 524:
            return "A Timeout Occurred (Cloudflare)";
            case 525:
            return "SSL Handshake Failed (Cloudflare)";
            case 526:
            return "Invalid SSL Certificate (Cloudflare)";
            case 527:
            return "Railgun Error (Cloudflare)";
            default:
            return "Unknown Error";
        }
    }
</script>